﻿using System;
using System.Linq.Expressions;

namespace UnitBox {
	internal class ConfigureLaterInterceptionBehaviour : ReturnlessInterceptionBehaviour {

		#region instance fields

		private readonly Expression<Action> _underlyingStaticCallExpression;
		private bool _isConfigured;
		private ReturnlessInterceptionBehaviour _returnlessInterceptionBehaviour;

		#endregion


		#region constructors

		public ConfigureLaterInterceptionBehaviour( Expression<Action> underlyingStaticCallExpression ) {
			_underlyingStaticCallExpression = underlyingStaticCallExpression;
		}

		#endregion


		#region public methods

		public void ConfigureWithInterceptionBehaviour( ReturnlessInterceptionBehaviour returnlessInterceptionBehaviour ) {
			// don't allow to configure twice
			if( _isConfigured )
				throw new InvalidOperationException( "Cannot configure more than once." );

			_returnlessInterceptionBehaviour = returnlessInterceptionBehaviour;

			// mark that this interception behaviour is configured
			_isConfigured = true;
		}


		public override void Invoke() {
			// invoke original if another interception has not been configured
			if( !_isConfigured ) {
				_underlyingStaticCallExpression.Compile().Invoke();
				return;
			}

			// otherwise delegate invocation to the configured interception
			_returnlessInterceptionBehaviour.Invoke();
		}

		#endregion

	}


	internal class ConfigureLaterInterceptionBehaviour<TReturnValue> : ValueReturningInterceptionBehaviour<TReturnValue> {

		#region instance fields

		private readonly Expression<Func<TReturnValue>> _underlyingStaticCallExpression;
		private bool _isConfigured;
		private ValueReturningInterceptionBehaviour<TReturnValue> _valueReturningInterceptionBehaviour;

		#endregion


		#region constructors

		#region constructors

		public ConfigureLaterInterceptionBehaviour( Expression<Func<TReturnValue>> underlyingStaticCallExpression ) {
			_underlyingStaticCallExpression = underlyingStaticCallExpression;
		}

		#endregion

		#endregion


		#region public methods

		public void ConfigureWithInterceptionBehaviour( ValueReturningInterceptionBehaviour<TReturnValue> valueReturningInterceptionBehaviour ) {
			// don't allow to configure twice
			if( _isConfigured )
				throw new InvalidOperationException( "Cannot configure more than once." );

			_valueReturningInterceptionBehaviour = valueReturningInterceptionBehaviour;

			// mark that this interception behaviour is configured
			_isConfigured = true;
		}


		public override TReturnValue Invoke() {
			// invoke original if another interception has not been configured
			if( !_isConfigured )
				return _underlyingStaticCallExpression.Compile().Invoke();

			// otherwise delegate invocation to the configured interception
			return _valueReturningInterceptionBehaviour.Invoke();
		}

		#endregion

	}
}
